package com.studyweb.exception;

import com.studyweb.pojo.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import java.util.Set;

/**
 * 全局异常处理器
 * 
 * <p>统一处理应用中的各种异常，确保返回一致的错误响应格式。</p>
 * <p>处理的异常类型包括：</p>
 * <ul>
 *   <li>参数校验异常（@RequestBody、@ModelAttribute、@RequestParam等）</li>
 *   <li>业务逻辑异常（IllegalArgumentException等）</li>
 *   <li>系统异常（NullPointerException、RuntimeException等）</li>
 *   <li>其他未知异常</li>
 * </ul>
 * 
 * @author StudyWeb Team
 * @since 1.0.0
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理参数校验异常（@RequestBody）
     * 
     * <p>当使用 @Valid 或 @Validated 注解校验 @RequestBody 参数失败时触发</p>
     * 
     * @param e MethodArgumentNotValidException 参数校验异常
     * @return Result 包含详细错误信息的统一响应
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        StringBuilder errorMsg = new StringBuilder();
        for (FieldError fieldError : e.getBindingResult().getFieldErrors()) {
            errorMsg.append(fieldError.getField())
                   .append(": ")
                   .append(fieldError.getDefaultMessage())
                   .append("; ");
        }
        
        String message = errorMsg.toString();
        if (message.endsWith("; ")) {
            message = message.substring(0, message.length() - 2);
        }
        
        log.warn("参数校验失败：{}", message);
        return Result.error("参数校验失败：" + message);
    }

    /**
     * 处理参数校验异常（@ModelAttribute）
     * 
     * <p>当使用 @ModelAttribute 绑定表单参数时发生校验错误时触发</p>
     * 
     * @param e BindException 参数绑定异常
     * @return Result 包含详细错误信息的统一响应
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result handleBindException(BindException e) {
        StringBuilder errorMsg = new StringBuilder();
        for (FieldError fieldError : e.getBindingResult().getFieldErrors()) {
            errorMsg.append(fieldError.getField())
                   .append(": ")
                   .append(fieldError.getDefaultMessage())
                   .append("; ");
        }
        
        String message = errorMsg.toString();
        if (message.endsWith("; ")) {
            message = message.substring(0, message.length() - 2);
        }
        
        log.warn("参数绑定失败：{}", message);
        return Result.error("参数绑定失败：" + message);
    }

    /**
     * 处理参数校验异常（@RequestParam、@PathVariable）
     * 
     * <p>当 @RequestParam 或 @PathVariable 参数不满足约束条件时触发</p>
     * 
     * @param e ConstraintViolationException 约束违反异常
     * @return Result 包含详细错误信息的统一响应
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result handleConstraintViolationException(ConstraintViolationException e) {
        StringBuilder errorMsg = new StringBuilder();
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            String propertyPath = violation.getPropertyPath().toString();
            String fieldName = propertyPath.substring(propertyPath.lastIndexOf('.') + 1);
            errorMsg.append(fieldName)
                   .append(": ")
                   .append(violation.getMessage())
                   .append("; ");
        }
        
        String message = errorMsg.toString();
        if (message.endsWith("; ")) {
            message = message.substring(0, message.length() - 2);
        }
        
        log.warn("参数约束违反：{}", message);
        return Result.error("参数约束违反：" + message);
    }

    /**
     * 处理非法参数异常
     * 
     * <p>当业务逻辑中检测到非法参数时触发</p>
     * 
     * @param e IllegalArgumentException 非法参数异常
     * @return Result 包含错误信息的统一响应
     */
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result handleIllegalArgumentException(IllegalArgumentException e) {
        log.warn("非法参数异常：{}", e.getMessage());
        return Result.error("参数错误：" + e.getMessage());
    }

    /**
     * 处理空指针异常
     * 
     * <p>当程序中出现空指针访问时触发，通常表示程序逻辑错误</p>
     * 
     * @param e NullPointerException 空指针异常
     * @return Result 包含错误信息的统一响应
     */
    @ExceptionHandler(NullPointerException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result handleNullPointerException(NullPointerException e) {
        log.error("空指针异常：{}", e.getMessage(), e);
        return Result.error("系统内部错误");
    }

    /**
     * 处理运行时异常
     * 
     * <p>处理其他未被特定处理器捕获的运行时异常</p>
     * 
     * @param e RuntimeException 运行时异常
     * @return Result 包含错误信息的统一响应
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result handleRuntimeException(RuntimeException e) {
        log.error("运行时异常：{}", e.getMessage(), e);
        return Result.error("系统运行异常：" + e.getMessage());
    }

    /**
     * 处理其他异常
     * 
     * <p>作为最后的异常处理器，捕获所有未被其他处理器处理的异常</p>
     * 
     * @param e Exception 通用异常
     * @return Result 包含错误信息的统一响应
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result handleException(Exception e) {
        log.error("系统异常：{}", e.getMessage(), e);
        return Result.error("系统异常，请联系管理员");
    }
}